package worker

import (
	"encoding/json"
	"executeserver/src/model"
	"executeserver/src/tool"
	"fmt"
	"log"
	"sort"
	"time"

	"github.com/go-redis/redis"
)

func ClearData(id int) {
	localRedis := model.GetLocalRedis()
	defer func() {
		localRedis.Close()
		log.Println("===cleardata is finished!===")
	}()
	// redisStr := `{"host":"127.0.0.1","port":6379,"password":"aa778899"}` // `{"host":"127.0.0.1,"port":6379,"password":"aa778899"}`
	clearKey := fmt.Sprintf(`statusInfo_%d`, id)
	// 开启redis事务
	var needClearData TaskExecuteStatus
	fn := func(tx *redis.Tx) error {

		data, err := localRedis.HGetAll(clearKey).Result()
		if err != nil {
			log.Println("HGetAll clearKey  error ", err)
			return err
		}
		ms := tool.NewMapSorter(data)
		sort.Sort(ms)
		k, v := GetNeedClearData(ms)
		log.Println("fn is running", k, v)

		if k != "-1" {
			// 更改状态及删除时间
			v.DeletingStatus = true
			v.LastDeletingTime = time.Now()
			needClearData = v
			// runs only if the watched keys remain unchanged
			_, hsetErr := tx.Pipelined(func(pipe redis.Pipeliner) error {
				pipe.HSet(clearKey, fmt.Sprintf("%d", v.Version), data[k])
				return nil
			})
			return hsetErr
		} else {
			_, err = tx.Pipelined(func(pipe redis.Pipeliner) error {
				// pipe handles the error case
				pipe.HGetAll(clearKey)
				return nil
			})
			log.Println("hgetall", err)
			return err
		}
	}

	for canDelNumbs := 3; canDelNumbs > 0; canDelNumbs-- {
		err := localRedis.Watch(fn, clearKey)
		log.Println("localRedis.Watch error", err)
		// 数据没有被其他节点服务修改 执行删除操作
		if err == nil {
			// id=0是初始化值
			runClear(needClearData, clearKey)
		}
	}
	// localRedis.Close()
}

// 删除任务
func runClear(needClearData TaskExecuteStatus, clearKey string) {
	defer func() {
		log.Println("runclear is finished")
	}()
	log.Println("开始删除数据", needClearData.Id != 0)
	if needClearData.Id != 0 {
		expirationTime := needClearData.LastDeletingTime.Add(time.Duration(needClearData.SchedulePeriod) * time.Second)
		log.Println("expirationTime", expirationTime)
		for {
			select {
			case <-time.After(time.Since(expirationTime)):
				log.Println("now-expirationTime", time.Now(), expirationTime)
				log.Println("删除超时", needClearData.Id, needClearData.Version)
				return
			default:
				if needClearData.DataDestination == "mongodb" {
					// client := model.GetMysqlConn(needClearData.DestConnectionStr)
				} else {
					client := model.GetRedisConn(needClearData.DestConnectionStr, needClearData.Id, needClearData.SchedulePeriod)
					startTime := time.Now()
					redisKey := fmt.Sprintf("data_%d_%d_*", needClearData.Id, needClearData.Version)
					var cur uint64
					for {
						list, cursor, err := client.Scan(cur, redisKey, 1000).Result()
						log.Println("cursor", cursor)
						if err != nil {
							// client.Close()
							log.Println("redis clear data error: scan ", err)
							return
						}
						cur = cursor
						for _, v := range list {
							client.Del(v)
						}
						log.Printf("redis key:%s 删除成功,耗时：%v,数量：%d", redisKey, time.Now().Sub(startTime), len(list))
						if cur == 0 {
							// client.Close()
							log.Println("删除完成")
							client.HDel(clearKey, fmt.Sprintf("%d", needClearData.Version))
							return
						}
					}

				}
			}
		}

	}

}

// 获取需要删除的任务版本
func GetNeedClearData(data tool.MapSorter) (string, TaskExecuteStatus) {
	var dealData TaskExecuteStatus
	list := make(map[string]TaskExecuteStatus)
	var successNumbs int
	for _, v := range data {
		var t TaskExecuteStatus
		err := json.Unmarshal([]byte(v.Val), &t)
		if err != nil {
			log.Println("checkTaskStatus json.Unmarshal error ", err)
			return "-1", dealData
		}
		log.Println("t", t)
		list[v.Key] = t
		if t.FinishStatus {
			successNumbs++
		}
	}
	log.Println(list)
	// 数据错误且未被认领的任务
	for k, v := range list {
		if !v.FinishStatus && !v.DeletingStatus {

			return k, v
		}
	}
	// 数据错误且被认领但是已经超时
	for k, v := range list {
		if !v.FinishStatus && (v.DeletingStatus && time.Now().After(v.LastDeletingTime.Add(time.Duration(v.SchedulePeriod)*time.Second))) {
			return k, v
		}
	}
	// 数据正确且被认领但是已经超时
	for k, v := range list {
		if v.FinishStatus && (v.DeletingStatus && time.Now().After(v.LastDeletingTime.Add(time.Duration(v.SchedulePeriod)*time.Second))) {
			return k, v
		}
	}
	// 数据正确且未被认领且早于最近完成3个TaskID的任务
	for k, v := range list {
		if v.FinishStatus && (!v.DeletingStatus && successNumbs > 3) {
			return k, v
		}
	}
	return "-1", dealData
}
